package com.kssoft.ebd.spider.head;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.client.ClientUtil;
import net.lightbody.bmp.core.har.Har;
import net.lightbody.bmp.core.har.HarEntry;
import net.lightbody.bmp.core.har.HarRequest;
import org.openqa.selenium.By;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TokenSpider implements PageProcessor {

    private static final Logger logger = Logger.getLogger(TokenSpider.class.getName());
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    // 代理池
    private List<String> proxyList = Lists.newArrayList(
            "http://123.45.67.89:8080"
    );
    
    // User-Agent池
    private List<String> userAgents = Lists.newArrayList(
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"
    );
    
    // 当前使用的代理
    private String currentProxy;
    // BrowserMob代理服务器
    private BrowserMobProxy proxyServer;
    // WebDriver实例
    private WebDriver driver;
    // 爬取结果列表
    private List<Map<String, Object>> results = new ArrayList<>();
    
    // 站点配置
    private Site site = Site.me()
            .setRetryTimes(3)
            .setSleepTime(1000)
            .setUserAgent(getRandomUserAgent());
    
    @Override
    public void process(Page page) {
        String url = page.getUrl().toString();
        logger.info("开始处理URL: " + url);
        
        try {
            // 初始化代理和浏览器
            initProxyAndDriver();
            
            // 使用Selenium加载页面
            loadPageWithSelenium(url);
            
            // 等待页面加载完成
            waitForPageLoad();
            
            // 捕获请求头并提取Token
            Map<String, Object> result = captureRequestHeadersAndToken(url);
            results.add(result);
            
            logger.info("处理完成: " + url + ", Token: " + (result.get("token") != null ? "已获取" : "未找到"));
        } catch (Exception e) {
            logger.severe("处理URL时发生错误: " + url + ", 错误信息: " + e.getMessage());
            results.add(Collections.singletonMap("error", "处理失败: " + e.getMessage()));
        } finally {
            // 清理资源
            cleanUp();
        }
    }
    
    @Override
    public Site getSite() {
        return site;
    }
    
    /**
     * 初始化代理和WebDriver
     */
    private void initProxyAndDriver() {
        // 关闭之前的代理和浏览器
        cleanUp();
        
        // 随机选择代理
        currentProxy = selectRandomProxy();
        logger.info("选择代理: " + currentProxy);
        
        // 启动BrowserMob代理服务器
        proxyServer = new BrowserMobProxyServer();
        proxyServer.setTrustAllServers(true);
        proxyServer.start(0); // 随机端口
        
        // 配置Selenium代理
        Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxyServer);
        seleniumProxy.setHttpProxy(currentProxy);
        seleniumProxy.setSslProxy(currentProxy);
        
        // 配置Chrome选项
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--headless");
        options.addArguments("--disable-gpu");
        options.addArguments("--window-size=1920,1080");
        options.addArguments("--no-sandbox");
        options.addArguments("--disable-dev-shm-usage");
        options.addArguments("user-agent=" + getRandomUserAgent());
        options.setCapability("proxy", seleniumProxy);
        
        // 初始化WebDriver
        System.setProperty("webdriver.chrome.driver", "D:\\soft\\chromedriver-win64\\chromedriver.exe"); // 替换为实际驱动路径
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        
        logger.info("代理和WebDriver初始化完成");
    }
    
    /**
     * 随机选择代理
     */
    private String selectRandomProxy() {
        if (proxyList.isEmpty()) {
            return null;
        }
        return proxyList.get(new Random().nextInt(proxyList.size()));
    }
    
    /**
     * 随机选择User-Agent
     */
    private String getRandomUserAgent() {
        if (userAgents.isEmpty()) {
            return "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
        }
        return userAgents.get(new Random().nextInt(userAgents.size()));
    }
    
    /**
     * 使用Selenium加载页面
     */
    private void loadPageWithSelenium(String url) {
        logger.info("加载页面: " + url);
        driver.get(url);
    }
    
    /**
     * 等待页面加载完成
     */
    private void waitForPageLoad() {
        try {
            // 等待页面加载完成，这里以等待body元素为例
            WebDriverWait wait = new WebDriverWait(driver, 10);
            wait.until(ExpectedConditions.presenceOfElementLocated(By.tagName("body")));
            logger.info("页面元素加载完成");
            
            // 额外等待，确保所有资源加载完毕
            Thread.sleep(2000);
        } catch (Exception e) {
            logger.warning("等待页面加载时发生异常: " + e.getMessage());
        }
    }
    
    /**
     * 捕获请求头并提取Token
     */
    private Map<String, Object> captureRequestHeadersAndToken(String url) {
        Map<String, Object> result = new HashMap<>();
        result.put("url", url);
        result.put("proxy_used", currentProxy);
        
        try {
            // 生成HAR日志
            proxyServer.newHar("token-capture");
            Har har = proxyServer.getHar();
            
            // 解析HAR日志获取请求头
            List<HarEntry> entries = har.getLog().getEntries();
            Map<String, String> headers = new HashMap<>();
            
            for (HarEntry entry : entries) {
                HarRequest request = entry.getRequest();
                request.getHeaders().forEach(h -> headers.put(h.getName(), h.getValue()));
                
                // 提取Token
                String token = extractTokenFromHeaders(headers);
                if (token != null) {
                    result.put("token", token);
                    result.put("headers", headers);
                    return result;
                }
            }
            
            // 未找到Token
            result.put("token", null);
            result.put("headers", headers);
            logger.warning("未在请求头中找到Token");
        } catch (Exception e) {
            logger.severe("捕获请求头时发生错误: " + e.getMessage());
            result.put("error", "捕获请求头失败: " + e.getMessage());
        }
        
        return result;
    }
    
    /**
     * 从请求头中提取Token
     */
    private String extractTokenFromHeaders(Map<String, String> headers) {
        // 常见的Token头名称
        String[] tokenKeys = {
            "Authorization", "X-Auth-Token", "X-API-KEY", "Token",
            "Access-Token", "Bearer", "JWT", "api_key"
        };
        
        for (String key : tokenKeys) {
            if (headers.containsKey(key)) {
                return headers.get(key);
            }
            
            // 不区分大小写查找
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                if (entry.getKey().equalsIgnoreCase(key)) {
                    return entry.getValue();
                }
            }
        }
        
        // 检查Cookie中的Token
        if (headers.containsKey("Cookie")) {
            String[] cookies = headers.get("Cookie").split("; ");
            for (String cookie : cookies) {
                if (cookie.toLowerCase().contains("token") || cookie.toLowerCase().contains("auth")) {
                    return cookie;
                }
            }
        }
        
        return null;
    }
    
    /**
     * 清理资源
     */
    private void cleanUp() {
        try {
            if (proxyServer != null && proxyServer.isStarted()) {
                proxyServer.stop();
                logger.info("BrowserMob代理服务器已关闭");
            }
            
            if (driver != null) {
                driver.quit();
                logger.info("WebDriver已关闭");
            }
        } catch (Exception e) {
            logger.severe("清理资源时发生错误: " + e.getMessage());
        }
    }
    
    /**
     * 获取爬取结果
     */
    public List<Map<String, Object>> getResults() {
        return results;
    }
    
    /**
     * 主方法示例
     */
    public static void main(String[] args) {
        // 配置日志级别
        Logger rootLogger = Logger.getLogger("");
        rootLogger.setLevel(Level.INFO);
        
        // 目标URL列表
        List<String> targetUrls = Arrays.asList(
            "https://192.168.0.223:1443/#/"
        );
        
        // 初始化爬虫
        TokenSpider spider = new TokenSpider();
        
        // 配置代理池（示例中使用占位符，实际使用时请替换为真实代理）
        spider.proxyList = Arrays.asList(
            "http://123.45.67.89:8080"
        );
        
        // 运行爬虫
        Spider.create(spider)
            .addUrl(targetUrls.toArray(new String[0]))
            .thread(1) // 单线程，因为Selenium操作是单线程的
            .run();
        
        // 输出结果
        System.out.println("爬取结果:");
        try {
            System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(spider.getResults()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}